using DeviceCommons.DataHandling;
using DeviceCommons.DeviceMessages.Builders;
using DeviceCommons.DeviceMessages.Enums;
using DeviceCommons.DeviceMessages.Models.V1;
using DeviceCommons.DeviceMessages.Serialization;
using System.Buffers;
using Xunit.Abstractions;

namespace DeviceCommons.Tests.Shared
{
    /// <summary>
    /// 基础测试类，提供共享的测试基础设施和工具方法
    /// </summary>
    public abstract class BaseTestClass : IDisposable
    {
        protected readonly ITestOutputHelper Output;
        protected readonly IDeviceMessageParser Parser;
        protected readonly IDeviceMessageSerializer Serializer;
        protected readonly ArrayBufferWriter<byte> BufferWriter;

        protected BaseTestClass(ITestOutputHelper output)
        {
            Output = output;
            Parser = DeviceMessageSerializerProvider.MessagePar;
            Serializer = DeviceMessageSerializerProvider.MessageSer;
            BufferWriter = new ArrayBufferWriter<byte>();
        }

        /// <summary>
        /// 创建基础的消息构建器
        /// </summary>
        /// <param name="deviceId">设备ID</param>
        /// <param name="deviceType">设备类型</param>
        /// <param name="version">协议版本</param>
        /// <param name="crcType">CRC类型</param>
        /// <returns>配置好的消息构建器</returns>
        protected IDeviceMessageBuilder CreateBasicBuilder(
            string deviceId = "TestDevice",
            byte deviceType = 0x01,
            byte version = 0x02,
            CRCTypeEnum crcType = CRCTypeEnum.CRC16)
        {
            return (IDeviceMessageBuilder)DeviceMessageBuilder.Create()
                .WithHeader(version: version, crcType: crcType)
                .WithMainDevice(deviceId, deviceType);
        }

        /// <summary>
        /// 创建包含基础读数的消息构建器
        /// </summary>
        /// <param name="deviceId">设备ID</param>
        /// <param name="deviceType">设备类型</param>
        /// <returns>包含基础读数的消息构建器</returns>
        protected IDeviceMessageBuilder CreateBuilderWithBasicReading(
            string deviceId = "TestDevice",
            byte deviceType = 0x01)
        {
            return (IDeviceMessageBuilder)CreateBasicBuilder(deviceId, deviceType)
                .WithMainDevice(deviceId, deviceType, config =>
                {
                    config.AddReading(100, reading =>
                    {
                        reading.AddState(1, "Test Value", StateValueTypeEnum.String);
                        reading.AddState(2, 42, StateValueTypeEnum.Int32);
                        reading.AddState(3, true, StateValueTypeEnum.Bool);
                    });
                });
        }

        /// <summary>
        /// 执行消息的序列化和反序列化往返测试
        /// </summary>
        /// <param name="builder">消息构建器</param>
        /// <returns>解析后的消息</returns>
        protected IDeviceMessage PerformRoundTripTest(IDeviceMessageBuilder builder)
        {
            // 构建消息
            var originalMessage = (DeviceMessage)builder.Build();

            // 序列化
            BufferWriter.Clear();
            Serializer.Serializer(BufferWriter, originalMessage);
            var bytes = BufferWriter.WrittenSpan.ToArray();

            // 反序列化
            var parsedMessage = (IDeviceMessage)Parser.Parser(bytes);

            // 基础验证
            Assert.NotNull(parsedMessage);
            Assert.Equal(originalMessage.Header.Version, parsedMessage.Header.Version);
            Assert.Equal(originalMessage.Header.CRCType, parsedMessage.Header.CRCType);
            Assert.Equal(originalMessage.MainDevice.DID, parsedMessage.MainDevice.DID);
            Assert.Equal(originalMessage.MainDevice.DeviceType, parsedMessage.MainDevice.DeviceType);

            Output.WriteLine($"Round-trip test passed for device: {parsedMessage.MainDevice.DID}");
            Output.WriteLine($"Serialized size: {bytes.Length} bytes");

            return parsedMessage;
        }

        /// <summary>
        /// 测试消息的十六进制序列化
        /// </summary>
        /// <param name="builder">消息构建器</param>
        /// <param name="compress">是否压缩</param>
        /// <param name="encrypt">是否加密</param>
        /// <param name="password">加密密码（可选，默认使用系统默认密码）</param>
        /// <returns>十六进制字符串和解析后的消息</returns>
        protected (string hex, IDeviceMessage parsed) PerformHexTest(
            IDeviceMessageBuilder builder, 
            bool compress = false, 
            bool encrypt = false,
            string? password = null)
        {
            string hex;
            if (encrypt && password != null)
            {
                // 使用新的API传递密码
                hex = builder.BuildHex(compress, encrypt, password);
            }
            else
            {
                // 使用传统的API（默认密码或预设加密函数）
                hex = builder.BuildHex(compress, encrypt);
            }
            
            Assert.NotNull(hex);
            Assert.NotEmpty(hex);

            IDeviceMessage parsedMessage;
            if (encrypt)
            {
                // 当使用加密时，使用ParseFromHex方法来处理解密
                // 如果没有提供密码，则传递null让框架内部处理默认密码
                parsedMessage = ParseFromHex(hex, password);
            }
            else
            {
                parsedMessage = (IDeviceMessage)Parser.Parser(hex);
            }
            
            Assert.NotNull(parsedMessage);

            Output.WriteLine($"Hex test passed. Length: {hex.Length} chars");
            if (compress) Output.WriteLine("✓ Compression enabled");
            if (encrypt) Output.WriteLine("✓ Encryption enabled");
            if (encrypt && password != null) Output.WriteLine($"✓ Custom password: {password.Substring(0, Math.Min(4, password.Length))}***");

            return (hex, parsedMessage);
        }

        /// <summary>
        /// 验证状态值
        /// </summary>
        /// <param name="states">状态数组</param>
        /// <param name="sid">状态ID</param>
        /// <param name="expectedValue">期望值</param>
        /// <param name="expectedType">期望类型</param>
        protected void VerifyState(
            IDeviceMessageInfoReadingState[] states,
            byte sid,
            object expectedValue,
            StateValueTypeEnum expectedType)
        {
            var state = states.FirstOrDefault(s => s.SID == sid);
            Assert.NotNull(state);
            Assert.Equal(expectedType, state.ValueType);

            switch (expectedType)
            {
                case StateValueTypeEnum.Binary:
                    // 处理二进制数据的类型转换
                    byte[] actualBytes;
                    var stateValue = state.Value;
                    if (stateValue is byte[] directBytes)
                    {
                        actualBytes = directBytes;
                    }
                    else if (stateValue.GetType() == typeof(ReadOnlyMemory<byte>))
                    {
                        actualBytes = ((ReadOnlyMemory<byte>)stateValue).ToArray();
                    }
                    else if (stateValue.GetType() == typeof(Memory<byte>))
                    {
                        actualBytes = ((Memory<byte>)stateValue).ToArray();
                    }
                    else
                    {
                        // 尝试直接转换
                        actualBytes = (byte[])stateValue;
                    }
                    Assert.Equal((byte[])expectedValue, actualBytes);
                    break;
                    
                case StateValueTypeEnum.String:
                    Assert.Equal(expectedValue.ToString(), state.ValueText);
                    break;
                    
                case StateValueTypeEnum.Bool:
                    // 处理布尔值
                    if (expectedValue is bool expectedBool)
                    {
                        var actualBoolText = state.ValueText?.ToString();
                        var actualBool = bool.Parse(actualBoolText ?? "false");
                        Assert.Equal(expectedBool, actualBool);
                    }
                    else
                    {
                        Assert.Equal(expectedValue.ToString(), state.ValueText);
                    }
                    break;
                    
                case StateValueTypeEnum.Int32:
                    // 处理32位整数
                    if (expectedValue is int expectedInt)
                    {
                        var actualIntText = state.ValueText?.ToString();
                        var actualInt = int.Parse(actualIntText ?? "0");
                        Assert.Equal(expectedInt, actualInt);
                    }
                    else
                    {
                        Assert.Equal(expectedValue.ToString(), state.ValueText);
                    }
                    break;
                    
                case StateValueTypeEnum.Int16:
                    // 处理16位整数
                    if (expectedValue is short expectedShort)
                    {
                        var actualShortText = state.ValueText?.ToString();
                        var actualShort = short.Parse(actualShortText ?? "0");
                        Assert.Equal(expectedShort, actualShort);
                    }
                    else
                    {
                        Assert.Equal(expectedValue.ToString(), state.ValueText);
                    }
                    break;
                    
                case StateValueTypeEnum.UInt16:
                    // 处理无符号16位整数
                    if (expectedValue is ushort expectedUShort)
                    {
                        var actualUShortText = state.ValueText?.ToString();
                        var actualUShort = ushort.Parse(actualUShortText ?? "0");
                        Assert.Equal(expectedUShort, actualUShort);
                    }
                    else
                    {
                        Assert.Equal(expectedValue.ToString(), state.ValueText);
                    }
                    break;
                    
                case StateValueTypeEnum.Timestamp:
                    // 处理时间戳
                    if (expectedValue is ulong expectedULong)
                    {
                        var actualULongText = state.ValueText?.ToString();
                        var actualULong = ulong.Parse(actualULongText ?? "0");
                        Assert.Equal(expectedULong, actualULong);
                    }
                    else
                    {
                        Assert.Equal(expectedValue.ToString(), state.ValueText);
                    }
                    break;
                    
                case StateValueTypeEnum.Float32:
                    // 处理单精度浮点数
                    if (expectedValue is float expectedFloat)
                    {
                        var actualFloatText = state.ValueText?.ToString();
                        var actualFloat = float.Parse(actualFloatText ?? "0");
                        Assert.True(Math.Abs(expectedFloat - actualFloat) < 0.001f, 
                            $"Expected {expectedFloat}, but got {actualFloat}");
                    }
                    else
                    {
                        Assert.Equal(expectedValue.ToString(), state.ValueText);
                    }
                    break;
                    
                case StateValueTypeEnum.Double:
                    // 处理双精度浮点数
                    if (expectedValue is double expectedDouble)
                    {
                        var actualDoubleText = state.ValueText?.ToString();
                        var actualDouble = double.Parse(actualDoubleText ?? "0");
                        Assert.True(Math.Abs(expectedDouble - actualDouble) < 0.000001, 
                            $"Expected {expectedDouble}, but got {actualDouble}");
                    }
                    else
                    {
                        Assert.Equal(expectedValue.ToString(), state.ValueText);
                    }
                    break;
                    
                default:
                    // 其他类型默认使用字符串比较
                    Assert.Equal(expectedValue.ToString(), state.ValueText);
                    break;
            }
        }

        /// <summary>
        /// 记录测试执行时间
        /// </summary>
        /// <param name="action">要执行的操作</param>
        /// <param name="description">操作描述</param>
        /// <returns>执行时间（毫秒）</returns>
        protected long MeasureExecutionTime(Action action, string description)
        {
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();
            action();
            stopwatch.Stop();

            Output.WriteLine($"{description}: {stopwatch.ElapsedMilliseconds}ms");
            return stopwatch.ElapsedMilliseconds;
        }

        /// <summary>
        /// 异步记录测试执行时间
        /// </summary>
        /// <param name="asyncAction">要执行的异步操作</param>
        /// <param name="description">操作描述</param>
        /// <returns>执行时间（毫秒）</returns>
        protected async Task<long> MeasureExecutionTimeAsync(Func<Task> asyncAction, string description)
        {
            var stopwatch = System.Diagnostics.Stopwatch.StartNew();
            await asyncAction();
            stopwatch.Stop();

            Output.WriteLine($"{description}: {stopwatch.ElapsedMilliseconds}ms");
            return stopwatch.ElapsedMilliseconds;
        }

        /// <summary>
        /// 从十六进制字符串解析消息
        /// </summary>
        /// <param name="hex">十六进制字符串</param>
        /// <param name="password">解密密码（可选）</param>
        /// <returns>解析后的消息</returns>
        protected IDeviceMessage ParseFromHex(string hex, string? password = null)
        {
            if (!string.IsNullOrEmpty(password))
            {
                // 当提供密码时，创建新的Parser实例以避免全局DecryptFunc的干扰
                var parser = new DeviceCommons.DeviceMessages.Serialization.DeviceMessageParser();
                return (IDeviceMessage)parser.Parser(hex, password);
            }
            
            // 使用全局Parser实例（已配置默认解密函数）
            return (IDeviceMessage)Parser.Parser(hex, password);
        }

        /// <summary>
        /// 从十六进制字符串异步解析消息
        /// </summary>
        /// <param name="hex">十六进制字符串</param>
        /// <param name="password">解密密码（可选）</param>
        /// <returns>解析后的消息</returns>
        protected async Task<IDeviceMessage> ParseFromHexAsync(string hex, string? password = null)
        {
            if (!string.IsNullOrEmpty(password))
            {
                // 当提供密码时，创建新的Parser实例以避免全局DecryptFunc的干扰
                var parser = new DeviceCommons.DeviceMessages.Serialization.DeviceMessageParser();
                return (IDeviceMessage)await parser.ParserAsync(hex, password);
            }
            
            // 使用全局Parser实例（已配置默认解密函数）
            return (IDeviceMessage)await Parser.ParserAsync(hex, password);
        }

        /// <summary>
        /// 测试自定义加密方法使用默认密码的场景
        /// </summary>
        /// <param name="builder">消息构建器</param>
        /// <param name="customEncryptFunc">自定义加密函数</param>
        /// <param name="customDecryptFunc">自定义解密函数</param>
        /// <returns>十六进制字符串和解析后的消息</returns>
        protected (string hex, IDeviceMessage parsed) PerformCustomEncryptionWithDefaultPasswordTest(
            IDeviceMessageBuilder builder,
            Func<string, string, string> customEncryptFunc,
            Func<string, string, string> customDecryptFunc)
        {
            // 使用自定义加密方法但使用默认密码
            builder.WithCustomEncryptionUsingDefaultPassword(customEncryptFunc, customDecryptFunc);
            
            var hex = builder.BuildHex(compress: false, encrypt: true);
            
            Assert.NotNull(hex);
            Assert.NotEmpty(hex);
            Assert.StartsWith("enc,raw|", hex); // 验证是加密的

            // 解析时使用独立的解析器实例，并配置自定义解密函数
            // 使用框架的默认解密机制，而不是直接访问内部常量
            var parser = new DeviceMessageParser();
            parser.DecryptFunc = cipherText => customDecryptFunc(cipherText, null); // 传递null让自定义解密函数使用默认密码
            var parsedMessage = (IDeviceMessage)parser.Parser(hex);
            Assert.NotNull(parsedMessage);

            Output.WriteLine($"Custom Encryption + Default Password test passed");
            Output.WriteLine($"Hex length: {hex.Length} chars");

            return (hex, parsedMessage);
        }

        /// <summary>
        /// 测试默认AES加密方法使用自定义密码的场景
        /// </summary>
        /// <param name="builder">消息构建器</param>
        /// <param name="customPassword">自定义密码</param>
        /// <returns>十六进制字符串和解析后的消息</returns>
        protected (string hex, IDeviceMessage parsed) PerformDefaultAesWithCustomPasswordTest(
            IDeviceMessageBuilder builder,
            string customPassword)
        {
            // 使用默认AES加密方法但使用自定义密码
            // 这里不调用WithAesEncryption，而是直接使用BuildHex的密码参数
            var hex = builder.BuildHex(compress: false, encrypt: true, encryptionPassword: customPassword);
            
            Assert.NotNull(hex);
            Assert.NotEmpty(hex);
            Assert.StartsWith("enc,raw|", hex); // 验证是加密的

            // 解析时也使用相同的自定义密码
            var parsedMessage = ParseFromHex(hex, customPassword);
            Assert.NotNull(parsedMessage);

            Output.WriteLine($"Default AES + Custom Password test passed");
            Output.WriteLine($"Custom password: {customPassword.Substring(0, Math.Min(4, customPassword.Length))}***");
            Output.WriteLine($"Hex length: {hex.Length} chars");

            return (hex, parsedMessage);
        }

        public virtual void Dispose()
        {
            // ArrayBufferWriter<byte> 不实现 IDisposable，所以不需要调用 Dispose
            // BufferWriter?.Dispose();
        }
    }
}